package com.onefish.toolkit.attack;

import java.io.*;
import java.lang.reflect.Constructor;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * 单例
 */
public class Singleton implements Serializable {
    private static final long serialVersionUID = 1L;
    private static Singleton instance;

    private Singleton() {
        // 防止通过反射创建实例或通过枚举获取单例是安全的
//        if (instance != null) {
//            throw new IllegalStateException("Instance already exists!");
//        }
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

    public void doSomething() {
        System.out.println("Singleton instance is doing something.");
    }

    public static void main(String[] args) throws Exception {
        //  Reflect attack
        Singleton singleton1 = Singleton.getInstance();
        Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        Singleton singleton2 = constructor.newInstance();
        System.out.println("A singleton created by reflection is the same as another instance: " + (singleton1 == singleton2));
        singleton1.doSomething();
        singleton2.doSomething();
        //  Serialization attack
        Singleton singleton3 = Singleton.getInstance();
        Singleton singleton4;
        try (ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(Paths.get("singleton.ser")))) {
            out.writeObject(singleton3);
        }
        try (ObjectInputStream in = new ObjectInputStream(Files.newInputStream(Paths.get("singleton.ser")))) {
            singleton4 = (Singleton) in.readObject();
        }
        System.out.println("A singleton created by Serialization is the same as another instance:" + (singleton3 == singleton4));
        singleton3.doSomething();
        singleton4.doSomething();
    }
}
